﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Xml.Linq;
using Grundy.Common;
using Grundy.CryptographicServices;
using Grundy.Licensing.Server.Command;
using Grundy.Message;
using Grundy.Message.Licensing;
using Grundy.Net;
using System.Linq;
using log4net;
using FluentValidation;

namespace Grundy.Licensing.Server
{
    public class LicenseService : IMessageHandler
    {
        ILog _logger = log4net.LogManager.GetLogger(typeof(LicenseService));

        private readonly List<ICommand> _commands;

        public LicenseService(IEnumerable<ICommand> commands)
        {
            _commands = commands.ToList();
        }

        public string ProcessMessage(string message, EndPoint client)
        {
            CustomerCryptographicServicesProvider ccsp = null;
            var application = Application.Instance;

            var emscsp = application.EntitlementServerCryptographicServicesProvider;
            var scsp = application.ServerCryptographicServicesProvider;
            Container c = null;
            Response response = null;

            try
            {
                c = message.Deserialize<Container>();
                ccsp = application.GetCustomerCryptographicServicesProvider(c.Provider);
            }
            catch (Exception ex)
            {
                _logger.ErrorFormat("Message received from {1} is not valid. Message: {2} {0}Details: {0}{3}", Environment.NewLine, client, ex.Message, ex);
                response = new  Error { Message = "Message received from {0} is not valid.".FormatWith(client), Exception = ex.ToString() };
            }

            if (c != null)
            {
                try
                {
                    var request = c.VerifyPayload<Request>(emscsp, scsp, ccsp);
                    if (request == null)
                    {
                        response = new Error { Message = "Container contains invalid data." };
                    }
                    else
                    {
                        var command = _commands.FirstOrDefault(i => i.CanProcess(request));
                        response = command == null ? new InvalidRequestError(request) : (request is LicenseRequest ? command.Process(request, client, ccsp.CustomerId, ccsp.CustomerName) : command.Process(request, client, Guid.Empty, string.Empty));
                        if (response is Success)
                        {
                            var success = (Success) response;
                            success.Challenge = request.Challenge;
                        }
                    }
                }
                catch (Exception ex)
                {
                    response = new Error {Message = ex.Message, Details = ex.ToString()};
                }
            }

                var responseContainer = scsp.Sign(response, ContainerSigneeType.Server);
                var responseMessage = responseContainer.Serialize();
                return responseMessage;
        }
    }
}